﻿using System;

namespace Geometry
{
    public class Point
    {
        #region 构造器
        public Point(string id, double x, double y)
        {
            ID = id;
            X = x;
            Y = y;
        }
        public Point(double x, double y)
        {
            X = x;
            Y = y;
        }
        public Point() { }
        #endregion

        #region 属性
        public string ID { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        #endregion

        #region 方法
        public void WriteLine()
        {
            Console.WriteLine("{0} ({1},{2})", ID, X, Y);
        }

        public void WriteLine(PointWtihLineStringRelEnum relEnum, string polylineID)
        {
            Console.WriteLine("点【{0}】与线【{1}】的拓扑关系是：{2}",
                ID, polylineID, relEnum);
        }

        public void WriteLine(PointWithPolygonRelEnum relEnum, string polygonID)
        {
            Console.WriteLine("点【{0}】与面【{1}】的拓扑关系是：{2}",
                ID, polygonID, relEnum);
        }

        public bool Equals(Point pointOther)
        {
            if (X == pointOther.X && Y == pointOther.Y)
                return true;
            else
                return false;
        }

        /// <summary>
        /// 获取两点间距离
        /// </summary>
        /// <param name="pointTo">终点</param>
        /// <returns>距离</returns>
        public double GetDistance(Point pointTo)
        {
            double x_2 = Math.Pow((this.X - pointTo.X), 2);
            double y_2 = Math.Pow((this.Y - pointTo.Y), 2);
            return Math.Sqrt((x_2) + (y_2));
        }

        public PointWtihLineStringRelEnum GetPointWithLineRel(Line line)
        {
            //1 与起点或者终点重合
            if (line.PointFrom.Equals(this) || line.PointTo.Equals(this))
                return PointWtihLineStringRelEnum.On_Line;
            //2 一般情况
            Vector v1 = new Vector("v1", this, line.PointFrom);
            Vector v2 = new Vector("v2", this, line.PointTo);
            double forkMultiply = v1.GetCrossProduct(v2);
            if (forkMultiply == 0)
            {
                if (line.IsPointInEnvelope(this))   //点在线上
                    return PointWtihLineStringRelEnum.On_Line;
                else if (v1.Norm < v2.Norm)         //后延伸线外
                    return PointWtihLineStringRelEnum.Out_BackExtend;
                else                                //前延伸线外
                    return PointWtihLineStringRelEnum.Out_ForwardExtend;
            }
            else if (forkMultiply > 0)  //左边
                return PointWtihLineStringRelEnum.Out_Left;
            else //右边
                return PointWtihLineStringRelEnum.Out_Right;
        }

        public PointWtihLineStringRelEnum GetPointWithPolylineRel(LineString polyline)
        {
            PointWtihLineStringRelEnum preRelEnum = PointWtihLineStringRelEnum.NULL;//前一个
            PointWtihLineStringRelEnum relEnum = PointWtihLineStringRelEnum.NULL;//当前
            for (int i = 1; i < polyline.PointList.Count; i++)
            {
                Point pointFrom = polyline.PointList[i - 1];
                Point pointTo = polyline.PointList[i];
                relEnum = GetPointWithLineRel(new Line(pointFrom, pointTo));
                //后延伸线外
                if (i == 1 && relEnum == PointWtihLineStringRelEnum.Out_BackExtend)
                    return relEnum;
                if (i == polyline.PointList.Count - 1 &&
                    relEnum == PointWtihLineStringRelEnum.Out_BackExtend)
                    return preRelEnum;
                preRelEnum = relEnum;
            }
            return relEnum;
        }

        public PointWithPolygonRelEnum GetPointWithPolygonRel(Polygon polygon)
        {
            try
            {
                PointWithPolygonRelEnum polygonRel = PointWithPolygonRelEnum.NULL;
                PointWtihLineStringRelEnum lineRel = PointWtihLineStringRelEnum.NULL;
                for (int i = 1; i < polygon.PointList.Count; i++)
                {
                    Point pointFrom = polygon.PointList[i - 1];
                    Point pointTo = polygon.PointList[i];
                    lineRel = GetPointWithLineRel(new Line(pointFrom, pointTo));
                    switch (lineRel)
                    {
                        case PointWtihLineStringRelEnum.On_Line:
                            return PointWithPolygonRelEnum.OnBoundary;
                        case PointWtihLineStringRelEnum.Out_Left:
                            polygonRel = PointWithPolygonRelEnum.Out;
                            break;
                        case PointWtihLineStringRelEnum.Out_Right:
                            polygonRel = PointWithPolygonRelEnum.In;
                            break;
                        default:
                            break;
                    }
                }
                return polygonRel;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return PointWithPolygonRelEnum.NULL;
            }
        }
        #endregion

    }
}